package top.chmin.project.cloud.sys.code;

import cn.hutool.core.bean.BeanUtil;
import jakarta.annotation.Resource;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import top.chmin.project.cloud.common.Page;
import top.chmin.project.cloud.sys.code.info.CodeInfo;
import top.chmin.project.cloud.sys.code.info.CodeInfoCondition;
import top.chmin.project.cloud.tool.DatetimeTool;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;


/**
 * chmin
 * 2024-01-26 14:00:51
 * cloud-code
 */
@Service
@Transactional
public class CodeService {

    @Resource
    CodePlugin plugin;

    public int save(CodeSaveRest.P p) {
        plugin.checkSave(p);
        Code code = BeanUtil.toBean(p, Code.class);
        plugin.beforeSave(code);
        int result = code.forInsert().execute();
        plugin.afterSave(p, code, result);
        return result;
    }

    public CodeSelectRest.R select(CodeSelectRest.P p) {
        plugin.checkSelect(p);
        CodeCondition c = CodeCondition.forSelect().id().eq(p.getId());
        plugin.beforeSelect(p, c);
        CodeSelectRest.R r = c.selectFirst(CodeSelectRest.R.class);
        plugin.afterSelect(p, r);
        return r;
    }

    public int update(CodeUpdateRest.P p) {
        plugin.checkUpdate(p);
        Code code = BeanUtil.toBean(p, Code.class);
        plugin.beforeUpdate(code);
        int result = code.forUpdate().id().eq().execute();
        plugin.afterUpdate(p, code, result);
        return result;
    }

    public int delete(CodeDeleteRest.P p) {
        plugin.checkDelete(p);
        Code code = BeanUtil.toBean(p, Code.class);
        plugin.beforeDelete(code);
        int result = code.forDelete().id().eq().execute();
        plugin.afterDelete(p, code, result);
        return result;
    }

    public Page<CodePageRest.R> page(CodePageRest.P p) {
        plugin.checkPage(p);
        CodeCondition c = CodeCondition.forSelect();
        c = p.isDesc() ? c.id().desc() : c.id().asc();
        plugin.beforePage(p, c);
        Page<CodePageRest.R> r = c.selectPage(CodePageRest.R.class);
        /*###########auto#start###########*/
        /*###########auto##end############*/
        /* append $serviceRelateAppender$ */
        /*###########auto#start###########*/
        /*###########auto##end############*/
        /* append $serviceDictAppender$ */
        plugin.afterPage(p, r);
        return r;
    }
    /* append $serviceSelectOptionMethodAppender$ */

    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public String getCode(String columnCode) {
        return getCodeList(columnCode, 1).getFirst();
    }

    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public List<String> getCodeList(String columnCode, int count) {
        CodeInfo codeInfo = CodeInfoCondition.forSelect().columnCode().eq(columnCode).selectFirst(CodeInfo.class);
        if (codeInfo == null) {
            throw new RuntimeException("编码配置未找到");
        }
        Code code;
        if (StringUtils.isEmpty(codeInfo.getDate())) {
            code = CodeCondition.forSelect().columnCode().eq(columnCode).selectFirst(Code.class);
        } else {
            code = CodeCondition.forSelect().columnCode().eq(columnCode).date().eq(DatetimeTool.format(LocalDateTime.now(), DatetimeTool.DateFormat.valueOf(codeInfo.getDate()))).selectFirst(Code.class);
        }
        if (code == null) {
            code = new Code()
                    .setColumnCode(columnCode)
                    .setPrefix(codeInfo.getPrefix())
                    .setDate(StringUtils.isEmpty(codeInfo.getDate()) ? "" : DatetimeTool.format(LocalDateTime.now(), DatetimeTool.DateFormat.valueOf(codeInfo.getDate())))
                    .setNextValue(codeInfo.getInitValue())
                    .setFixLength(codeInfo.getFixLength());
            code.forInsert().execute();
            return getCodeList(columnCode, count);
        }
        int oldNextValue = code.getNextValue();
        List<String> result = new ArrayList<>();
        while (result.size() < count) {
            result.add("%s%s%s".formatted(
                    code.getPrefix(),
                    code.getDate(),
                    StringUtils.leftPad(code.getNextValue() + "", code.getFixLength(), "0")
            ));
            code.setNextValue(code.getNextValue() + 1);
        }
        if (code.forUpdate().toFlex().nextValue().eq(oldNextValue).execute() == 0) {
            return getCodeList(columnCode, count);
        }
        return result;
    }
}
